import markup
import shutil
import datetime

from rsa import RSA_ROOT
from rsa.formatter.formatter import FormatterFactory
from rsa.util.robot_utilities import get_full_name

class Exporter(object):
    ''' 
    This is a template abstract class to export violations report into a given file 
    '''
    
    file = None
    
    def __init__(self, formatter):
        self.formatter = formatter
    
    def export_violations(self, report, path):
        ''' 
        Export in a given file a violations report 
        '''
        try:
            if(isinstance(path, list)):
                self.file = open(path[0], 'w')
            else:
                self.file = open(path, 'w')
            self.start(report)
            self.process(report)
            self.end(report)
            print
            print "report created in: '%s'" % path[0]
        except Exception, e:
            print "error writing in '%s':" % path, e
        finally:
            self.file.close()
            
    def start(self, report):
        '''
        Utility function to perform operations before processing the report
        '''
        pass
       
    def end(self, report):
        '''
        Utility function to perform operations after processing the report
        '''
        pass
    
    def process(self, report):
        ''' 
        Write in an external file a given report 
        '''
        raise NotImplementedError("Should have implemented this")
    
class SimpleExporter(Exporter):
    ''' 
    Export the report into a simple txt file 
    '''
    
    def process(self, report):
        for violation in report.violations:
            self.file.write(self.formatter.format(violation) + "\n")

class HTMLExporter(Exporter):
    ''' 
    Export the report to HTML file 
    '''
    
    # Variable definition
    errors = 0
    warnings = 0
    suggestions = 0
    
    page = None
    folder = None
    
    def start(self, report):
        file_name = self.file.name
        self.folder = file_name.rfind("/")
        self.folder = str(file_name[0:self.folder+1])
        shutil.copyfile(RSA_ROOT + "/resources/html_export.css",file_name + ".css")
        shutil.copyfile(RSA_ROOT + "/resources/html_export.js",file_name + ".js")  
        shutil.copyfile(RSA_ROOT + "/resources/folder_green.png",self.folder + "folder_green.png")
        shutil.copyfile(RSA_ROOT + "/resources/folder_green_open.png",self.folder + "folder_green_open.png")
        # Create the HTML page
        self.page = markup.page()
        self.page.html()
        self.page.head()
        # Add reference to the javascript file
        js_ref = '<script type="text/javascript" src="'+ file_name + ".js" +'"></script>'
        css_ref = '<link rel="stylesheet" href="'+ file_name + ".css" + '" type="text/css">'
        self.page.add(js_ref)
        self.page.add(css_ref)
        self.page.title("Robot Analyzer Report")
        self.page.head.close()
        self.page.body()
        # Append Report Data in a fieldset: Folder, Date and Rules
        self.page.fieldset()
        self.page.legend("<b>REPORT INFORMATION</b>")
        self.page.div(style="text-align:left;float:left;width:50%")
        self.page.p("<b>FOLDER:</b> " + report.validated_path)
        self.page.p("<b>INCLUDED RULES:</b> ")
        self.add_list(self.page, report.included_rules)
        self.page.div.close()
        self.page.div(style="text-align:left;float:right;width:50%")
        date = str(datetime.datetime.now())[0:10]
        self.page.p("<b>REPORT DATE:</b> " + date)
        self.page.p("<b>EXCLUDED RULES:</b> ")
        self.add_list(self.page, report.ignored_rules)
        self.page.div.close()
        self.page.fieldset.close()
        self.page.fieldset()
        # Append the Results Table in a new fieldset
        self.page.legend("<b>RESULTS</b>")
        self.page.a(id="ref_expand", href="#", onclick="expandAll('tableId');")
        self.page.add("Expand All")
        self.page.a.close()
        self.page.add("|")
        self.page.a(id="ref_colapse",href="#", onclick="collapseAll('tableId');")
        self.page.add("Collapse All")
        self.page.a.close()
        self.page.table(id="tableId")
        self.add_header_row(self.page)
        
    def process(self, report):
        # Violations must be ordered by path
        ordered_violations = self.order_violations(report.violations)
        # Last analyzed path
        last_test_path = []
        # Array to store the position reached at each level/sublevel
        level_indexes = []
        # Var to store the position of REAL VIOLATIONS and FOLDERS at the same deep level
        same_level_count = 0
        v_index = 0;
        while v_index <  len(ordered_violations):
            violation = ordered_violations[v_index]
            test_name = get_full_name(violation.test)
            actual_test_path =  test_name.split('.')
            # Index (Level) where the actual path differs from the path of the last added row
            different_level = self.get_similarity_level(last_test_path, actual_test_path)
            # Start Building this row (violation/folder) id
            actual_row_id = "row"
            # Copy the equal content from the last row
            for i in range(0, different_level):
                actual_row_id = actual_row_id + "." + str(level_indexes[i])
            # If i have the same path than the last row---> I'm a row (violation) at this same level (I have no childs)
            if(different_level == len(actual_test_path) and len(last_test_path) == len(actual_test_path)):
                actual_row_id = actual_row_id + "." + str(same_level_count)
                same_level_count = same_level_count + 1
                self.add_violation_row(self.page, violation, actual_row_id)
                v_index = v_index + 1
            else:                                                                                                                                
                # Create the different path levels---> I'm a row (folder) at a different level
                for i in range(different_level, len(actual_test_path)):
                    # If i go deeper in the hierarchy (This is a new sublevel)
                    if(i == len(level_indexes)):
                        level_indexes.append(same_level_count)
                        actual_row_id = actual_row_id + "." + str(same_level_count)
                    else:
                        # If this level already exists (This folder has a brother), 
                        # I take the brother's number and erase the sublevel info of his childs
                        level_indexes = level_indexes[0:i+1]
                        level_indexes[i] = level_indexes[i] + 1
                        actual_row_id = actual_row_id + "." + str(level_indexes[i])
                    # Actual Folder Name
                    folder_name = actual_test_path[i]
                    self.add_violation_row_folder(self.page, violation, actual_row_id, folder_name)
                    # This is a new Folder---> Restart the count for this level
                    same_level_count = 0
                last_test_path = actual_test_path
        self.page.table.close()
        self.page.fieldset.close()
        
    def end(self, report):
        # Append the Report Summary in a new field set
        self.page.fieldset()
        self.page.legend("<b>SUMMARY</b>")
        self.page.div(style="text-align:left;float:left;width:50%") 
        self.page.p("<b>PROBLEMS:</b> " + str(len(report.violations)))
        self.page.div.close()
        self.page.div(style="text-align:left;float:right;width:50%")
        itemsBySeverity = [ "Errors: "+str(self.errors),"Warnings: "+str(self.warnings),"Suggestions: "+str(self.suggestions)]
        self.page.p("<b>PROBLEMS BY SEVERITY:</b> ")
        self.add_list(self.page, itemsBySeverity)
        self.page.div.close()
        self.page.fieldset.close()
        self.page.body.close()
        self.page.html.close()
        print >> self.file, self.page
    
    def add_column(self, page, column_text):
        page.td(column_text)
        page.td.close()
    
    def add_display_column(self, page, column_text, row_id):
        tabs = ""
        tab_spaces = len(row_id.split('.')) - 2
        for _ in range (0, tab_spaces):
            tabs = tabs + "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
        row_id = "'" + row_id + "'"
        method = "toggle_row(" + row_id + ");"
        page.td(class_="folder_row")
        page.add(tabs)
        page.a(href="#", onclick=method)
        page.img (src="folder_green_open.png", alt="", width="16", height="16")
        page.add(column_text)
        page.td.close()
    
    def add_column_header(self, page, column_header):
        page.th(column_header)
        page.th.close()
        
    def add_header_row(self, page):
        page.tr(id="header_row")
        self.add_column_header(page, 'TEST PATH')
        self.add_column_header(page, 'SEVERITY')
        self.add_column_header(page, 'LINE')
        self.add_column_header(page, 'RULE')
        self.add_column_header(page, 'PROBLEM')
        self.add_column_header(page, 'SOLUTION')
        page.tr.close()
    
    def add_violation_row(self, page, violation, row_id):
        violation = self.formatter.format(violation) + "\n"
        fields = violation.split('&')
        if(fields[1] == "Error"):
            self.errors = self.errors + 1
        elif(fields[1] == "Warning"):
            self.warnings = self.warnings + 1
        else:
            self.suggestions = self.suggestions + 1
        page.tr(id=row_id)
        self.add_column(page, "");
        for field_index in range (1, len(fields)):
            self.add_column(page, fields[field_index])
        page.tr.close()
    
    def add_violation_row_folder(self, page, violation, row_id, folder_name):
        violation = self.formatter.format(violation) + "\n"
        fields = violation.split('&')
        page.tr(id=row_id)
        self.add_display_column(page, folder_name, row_id)
        for _ in range (1, len(fields)):
                self.add_column(page, "-")
        page.tr.close()
    
    def add_list(self, page, element_list):
        page.ul()
        page.li(element_list)
        page.ul.close()
    
    def order_violations(self, violations):
        ordered_violations = sorted(violations, key=lambda violation: get_full_name(violation.test))
        return ordered_violations    
    
    def get_similarity_level(self, old_array, new_array):
        # Returns the first level (index) where the arrays differ
        for level in range(0, len(new_array)):
            if(level == len(old_array) or old_array[level] != new_array[level]):
                return level
        return len(new_array)
            
class ExporterFactory(object):
    '''
    This class deals with the problem of creating output Formatters specifying 
    the class of object that will be created
    '''
    
    csv = "csv"
    text = "text"
    html = "html"
    
    def get_exporter(self, format=None):
        '''
        Returns a specific instance of Formatter, if the argument format is not
        specified return the default formatter (TextFormatter)
        '''
        if(not format or self.text in format or self.csv in format): 
            return SimpleExporter(FormatterFactory().get_formatter(format))
        else:
            return HTMLExporter(FormatterFactory().get_formatter(format))